public interface IMovementStrategy
{
  public void move();
}



class FollowingMovementStrategy implements IMovementStrategy, IObserver
{
  private final IMovable owner;
  private final Observable target;
  private static final double triggerDist = 25.0;
  
  public FollowingMovementStrategy(IMovable owner, Observable target)
  {
    if (target == null)
    {
      throw new IllegalArgumentException("target cannot be null");
    }
    this.target = target;
    this.targetPos = this.target.getPos();
    this.owner = owner;
  }
  
  public Observable getTarget()
  {
    return this.target;
  }
  
  public void move()
  {
  }
  
  private Vector2 targetPos;
  
  public void registerEvents()
  {
    this.target.register(this);
  }
  
  public void unregisterEvents()
  {
    this.target.unregister(this);
  }
  
  public void update()
  {
    this.targetPos = this.target.getPos();
    Vector2 current = this.owner.getPos();
    Vector2 tpos = this.targetPos;
    
    double dx = current.x - tpos.x;
    double dy = current.y - tpos.y;
    if (sqrt((float)(dx * dx + dy * dy)) < triggerDist)
    {
      this.owner.setPos(this.owner.getPos());
      return;
    }
    double nx = dx / 1.1 + tpos.x;
    double ny = dy / 1.1 + tpos.y;
    Vector2 newPos = new Vector2((int)nx, (int)ny);
    this.owner.setPos(newPos);
  }
}



class FallingMovementStrategy implements IMovementStrategy
{
  private final IMovable owner;
  
  public FallingMovementStrategy(IMovable owner)
  {
    this.owner = owner;
  }
  
  public void move()
  {
    Vector2 currentPos = this.owner.getPos();
    Vector2 newPos = new Vector2(currentPos.x, currentPos.y + 5);
    this.owner.setPos(newPos);
  }
}



class WalkingMovementStrategy implements IMovementStrategy
{
  private final IMovable owner;
  private final int direction;
  
  public WalkingMovementStrategy(IMovable owner)
  {
    this.owner = owner;
    this.direction = (Math.random() < 0.5) ? -1 : 1;
  }
  
  public void move()
  {
    Vector2 currentPos = this.owner.getPos();
    Vector2 newPos = new Vector2(currentPos.x + 5 * this.direction, currentPos.y);
    this.owner.setPos(newPos);
  }
}
